package com.tc.erp.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.tc.erp.dao.GenericDao;

/**
 * Implementation of GenericDao interface. It provides some common methods for
 * every dao class.
 * 
 * @author Peter.Shang@locisoftware.com
 * @date Apr 21, 2008
 * 
 * @param <T>
 * @param <ID>
 */
public class GenericDaoHibernate<T, ID extends Serializable> extends
		HibernateDaoSupport implements GenericDao<T, ID> {
	/**
	 * 
	 */
	private Class<T> persistentClass;

	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	public GenericDaoHibernate() {
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	/**
	 * Constructor that takes in a class to see which type of entity to persist
	 * 
	 * @param persistentClass
	 *            the class type you'd like to persist
	 */
	public GenericDaoHibernate(final Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}

	/**
	 * Persistent the entity to database
	 * 
	 * @param entity
	 */
	public T save(T entity) {
		super.getHibernateTemplate().saveOrUpdate(entity);
		return entity;
	}

	public T update(T entity) {
		super.getHibernateTemplate().update(entity);
		return entity;
	}

	/**
	 * Delete the given persistent instance.
	 */
	public void delete(ID id) {
		super.getHibernateTemplate().delete(this.get(id));
	}

	/**
	 * Get entity by id
	 * 
	 * @param id
	 */
	public T get(ID id) {
		T entity = (T) super.getHibernateTemplate().get(this.persistentClass,
				id);
		return entity;
	}

	/**
	 * Load entity by id
	 * 
	 * @param id
	 */
	public T load(ID id) {
		T entity = (T) super.getHibernateTemplate().load(this.persistentClass,
				id);
		return entity;
	}

	/**
	 * 
	 */
	public List<T> loadAll() {
		return (List<T>) super.getHibernateTemplate().loadAll(
				this.persistentClass);
	}

	/**
	 * Find entity by example
	 * 
	 * @param exampleInstance
	 * @param excludeProperty
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByExample(T exampleInstance, String... excludeProperty) {
		DetachedCriteria detachedCrit = DetachedCriteria
				.forClass(this.persistentClass);
		Example example = Example.create(exampleInstance);
		for (String exclude : excludeProperty) {
			example.excludeProperty(exclude);
		}

		detachedCrit.add(example);
		return (List<T>) getHibernateTemplate().findByCriteria(detachedCrit);
	}

	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(Criterion... criterion) {
		DetachedCriteria detachedCrit = DetachedCriteria
				.forClass(this.persistentClass);
		for (Criterion c : criterion) {
			detachedCrit.add(c);
		}
		return (List<T>) getHibernateTemplate().findByCriteria(detachedCrit);
	}

	/**
	 * Remove all objects from the org.hibernate.Session cache, and cancel all
	 * pending saves, updates and deletes
	 */
	public void clear() {
		super.getHibernateTemplate().clear();
	}

	/**
	 * Flush all pending saves, updates and deletes to the database.
	 */
	public void flush() {
		super.getHibernateTemplate().flush();
	}

	/**
	 * 
	 */
	public boolean exists(ID id) {
		return false;
	}

	@SuppressWarnings("unchecked")
	public List<T> load(int pageSize, int currentPage) {
		Criteria c = getSession().createCriteria(persistentClass);
		c.setFirstResult((currentPage - 1) * pageSize);
		c.setMaxResults(pageSize);
		return (List<T>) c.list();
	}

}
